﻿using Scenario_Editor.TerrainTools.TerrainGenerator;
using System;
using System.Windows.Forms;
using Tools;

namespace Scenario_Editor.CustomControls
{
    public partial class PerlinNoiseControl : UserControl, ITerrainGenerator
    {
        #region Private Fields

        private Random random;

        #endregion Private Fields

        #region Public Constructors

        public PerlinNoiseControl()
        {
            InitializeComponent();

            this.random = new Random();
        }

        #endregion Public Constructors

        #region Public Events

        public event EventHandler ValueChanged;

        #endregion Public Events

        #region Public Properties

        public string GeneratorName { get { return "Perlin Noise"; } }

        public int NumberOfBlocksX { get; set; }

        public int NumberOfBlocksY { get; set; }

        public float TerrainSizeX { get; set; }

        public float TerrainSizeY { get; set; }

        #endregion Public Properties

        #region Public Methods

        public float[,] GetValues()
        {
            float[,] sectorValues = new float[this.NumberOfBlocksX, this.NumberOfBlocksY];
            float frequency = (float)this.numericUpDown_Frequency.Value;
            float amplitude = (float)this.numericUpDown_Amplitude.Value;
            float persitance = (float)this.numericUpDown_Persistance.Value;
            int octaves = (int)this.numericUpDown_Oktaves.Value;
            float sizeX = TerrainSizeX / 10.0f;
            float sizeY = TerrainSizeY / 10.0f;
            PerlinNoise3D perlinNoise = new PerlinNoise3D((int)this.nud_Seed.Value, (int)Math.Max(sizeX, sizeY), 10);

            float factorX = sizeX / NumberOfBlocksX;
            float factorY = sizeY / NumberOfBlocksY;
            float min = float.MaxValue;
            float max = float.MinValue;
            for (int i = 0; i < 1; i++)
            {
                for (int x = 0; x < this.NumberOfBlocksX; x++)
                {
                    for (int y = 0; y < this.NumberOfBlocksY; y++)
                    {
                        float value = (float)(perlinNoise.GetValue(x * factorX, i * 100.0f, y * factorY, frequency, amplitude, persitance, octaves));
                        min = Math.Min(min, value);
                        max = Math.Max(max, value);
                        sectorValues[x, y] += value;
                    }
                }
            }

            // Normalisize between -1.0f and 1.0f
            float minValue = float.MaxValue;
            float maxValue = float.MinValue;
            for (int x = 0; x < this.NumberOfBlocksX; x++)
            {
                for (int y = 0; y < this.NumberOfBlocksY; y++)
                {
                    minValue = Math.Min(minValue, sectorValues[x, y]);
                    maxValue = Math.Max(maxValue, sectorValues[x, y]);
                }
            }

            float rangeMinMax = maxValue - minValue;

            float maxAbsolute = Math.Max(Math.Abs(maxValue), Math.Abs(minValue));

            for (int x = 0; x < this.NumberOfBlocksX; x++)
            {
                for (int y = 0; y < this.NumberOfBlocksY; y++)
                {
                    sectorValues[x, y] /= maxAbsolute;
                }
            }

            return sectorValues;
        }

        public override string ToString()
        {
            return "Perlin Noise";
        }

        #endregion Public Methods

        #region Private Methods

        private void button_NewRandom_Click(object sender, EventArgs e)
        {
            this.nud_Seed.Value = this.random.Next((int)this.nud_Seed.Minimum, (int)Math.Min(this.nud_Seed.Maximum, int.MaxValue));
        }

        private void lanel_Seed_Click(object sender, EventArgs e)
        {
        }

        private void OnValuesChanges(object sender, EventArgs e)
        {
            if (this.ValueChanged != null)
                this.ValueChanged(this, EventArgs.Empty);
        }

        #endregion Private Methods
    }
}